#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcre.h>
#include <mysql.h>


#define  OVECCOUNT 30 
#define  EBUFLEN  128
#define  BUFLEN  1024

/* 获取 show engine innodb status 状态信息*/
int innodb_status_value(void);
/* 获取状态值 */ 
float status_value(char *status);


int main (int argc, char * argv[]) 
{
  
  // innodb_status_value();
  float test = status_value("read_row_per_second");
  printf("test = %0.2f\n",test);
  return 0;
}

/* 获取 show engine innodb status 状态信息，将状态信息写到指定文本 */
int innodb_status_value(void)
{
  MYSQL *mysql;
  MYSQL_RES *res;
  MYSQL_ROW row;

  FILE *fd;

  pcre *re;
  const char *error;
  int erroffset;
  int ovector[OVECCOUNT];
  int rc,i;
  char matched[BUFLEN];
  char pattern[BUFLEN];

  char *src = NULL;
  src = (char *)malloc(1024);

  int j = 0;
  int length = 0;
  int len = 0;

  if( (fd = fopen("/tmp/.innodb_status","w+")) == NULL)
  {
    fprintf(stderr,"Can't open file!\n");
    return 1;
  }

  mysql = mysql_init(NULL);

  if(!mysql_real_connect(mysql,"192.168.65.224","shopex","shopex","test",3307,NULL,0))
  {
    fprintf(stderr,"%s\n",mysql_error(mysql));
  }

  /* 查询语句 */
  char *sql = "show engine innodb status";
  
  if(!mysql_query(mysql,sql))
  {
    res = mysql_store_result(mysql);
  }else
  {
    fprintf(stderr,"%s\n",mysql_error(mysql));
    exit(-1);
  }

  while(row = mysql_fetch_row(res))
  {
    //printf("%s\n",row[2]);
    src = row[2]; 
  }
 

  char *row_op_pattern[] = {"\\sibuf\\saio\\sreads:\\s(\\d+)",  //ibuf aio reads  FILE I/O
                            ",\\slog\\si/o's:\\s(\\d+)", // log i/o's
                            ",\\ssync\\si/o's:\\s(\\d+)",// sync i/o's
                            "\n(.*)OS\\sfile\\sreads", // OS file reads
                            ",\\s(\\d+)\\sOS\\sfile\\swrites", // OS file writes
                            ",\\s(\\d+)\\sOS\\sfsyncs", //OS fsyncs 
                            "(\\d+\\.\\d+)\\sreads/s", //FILE I/O  reads/s
                            ",\\s(\\d+)\\savg\\sbytes/read",//FILE I/O avg bytes/read
                            ",\\s(\\d+\\.\\d+)\\swrites/s", //FILE I/O  writes/s
                            ",\\s(\\d+\\.\\d+)\\sfsyncs/s", //FILE I/O fsyncs/s
                            "\\sinsert\\s(\\d+)",//INSERT BUFFER AND ADAPTIVE HASH INDEX.insert num of merged operations
                            ",\\sdelete\\smark\\s(\\d+)", // Delete mark
                            ",\\sdelete\\s(\\d+)", //delete 
                            "discarded\\soperations:\n\\sinsert\\s(\\d+)",//discarded operations: inserts/s
                            "discarded\\soperations:\n\\sinsert\\s(\\d+),\\sdelete\\smark\\s(\\d+)", //delete mark
                            "discarded\\soperations:\n\\sinsert\\s(\\d+),\\sdelete\\smark\\s(\\d+),\\sdelete\\s(\\d+)",//deleter
                            "(\\d+\\.\\d+)\\shash\\ssearches/s", //hash searches/s
                            ",\\s(\\d+\\.\\d+)\\snon-hash\\ssearches/s", //non-hash searches/s
                            ",\\s(\\d+\\.\\d+)\\slog\\si/o's/second",//LOG log i/o's/second
                            "Total\\smemory\\sallocated\\s(\\d+)",//BUFFER POOL AND MEMORY.Total memory allocated
                            "Dictionary\\smemory\\sallocated\\s(\\d+)", //Dictionary memory allocated
                            "Buffer\\spool\\ssize\\s+(\\d+)",//Buffer pool size   
                            "Free\\sbuffers\\s+(\\d+)",//Free buffers
                            "Database\\spages\\s+(\\d+)",//Database pages
                            "Old\\sdatabase\\spages\\s(\\d+)",//Old database pages
                            "Modified\\sdb\\spages\\s+(\\d+)",// Modified db pages
                            "\n(.*)\\syoungs/s", //youngs/s
                            ",\\s(\\d+\\.\\d+)\\snon-youngs/s", //non-youngs/s
                            "\n(.*)\\sreads/s", //Pages reads/s
                            ",\\s(\\d+\\.\\d+)\\screates/s", //Pages creates/s
                            ",\\s(\\d+\\.\\d+)\\swrites/s",//Pages writes/s
                            "Buffer\\spool\\shit\\srate\\s(\\d+\\s/\\s\\d+)", // Buffer pool hit rate
                            "Pages\\sread\\sahead\\s(\\d+\\.\\d+)/s", //Pages read ahead 0.00/s
                            ",\\sevicted\\swithout\\saccess\\s(\\d+\\.\\d+)/s", // evicted without access 0.00/s
                            ",\\sRandom\\sread\\sahead\\s(\\d+\\.\\d+)/s", //Random read ahead 0.00/s
                            "\n(.*)queries\\sinside\\sInnoDB,", //queries inside InnoDB  ROW OPERATIONS
                            ",\\s(\\d+)\\squeries\\sin\\squeue", //queries in queue
                            "Number\\sof\\srows\\sinserted\\s(\\d+)", //Number of rows inserted
                            ",\\supdated\\s(\\d+),", //Number of rows updated
                            ",\\sdeleted\\s(\\d+),", // Number of rows deleted
                            ",\\sread\\s(\\d+)",   //Number of rows read
                            "(\\d+\\.\\d+)\\sinserts/s",  // Insert row per second
                            ",\\s(\\d+\\.\\d+)\\supdates/s,",  //Update row per second
                            ",\\s(\\d+\\.\\d+)\\sdeletes/s,",  //Delete row per second
                            ",\\s(\\d+\\.\\d+)\\sreads/s"  //Read row per second
  };
  
  /* 获取指针数组元素的个数 */
  length = sizeof(row_op_pattern) / sizeof(char *);

  //printf("length = %d\n",length);

   for(j = 0;j < length;j++)
  {

    re = pcre_compile(row_op_pattern[j],0,&error,&erroffset,NULL);
    if(re  == NULL)
    {
      /* 有错误不退出，继续下个匹配 */
      printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
      //return 1;
    }
  
    rc  = pcre_exec(re,NULL,src,strlen(src),0,0,ovector,OVECCOUNT);

    if(rc < 0)
    {
      /* 匹配不成功，报错，不退出，继续下一个匹配 */
      if (rc == PCRE_ERROR_NOMATCH) printf("Sorry, no match ...\n");
      else    printf("Matching error %d\n", rc);
      //free(re);
      //return 1;
    }
  
    //printf("rc = %d\n",rc);
     
    for (i = 1; i < rc; i++) {
      char *substring_start = src + ovector[2*i];
      int substring_length = ovector[2*i+1] - ovector[2*i];
      len  = substring_length;
      //printf("%2d: %.*s\n", i, substring_length, substring_start);
      //printf("%d\n",substring_length);
      //printf("%.*s\n",substring_length,substring_start);
      memcpy(matched,substring_start,substring_length);
    }
    matched[len] = '\0';
    //printf("matched = %s\n",matched);
    //printf("%d\n",length);
    fwrite(matched,strlen(matched),1,fd);
    fwrite("\n",strlen("\n"),1,fd);
    }

   fclose(fd);
  free(re);
  mysql_close(mysql);
  return 0;
}

float status_value(char *status)
{
  FILE *fd;
  char buf[16];
  char ret[16];

  int len = 0;
  int i = 0;
  int j = 0;
  int arr_index = 0;
  
  printf("%s\n",status);

  if( (fd = fopen("/tmp/.innodb_status","r")) == NULL )
  {
    fprintf(stderr,"Can't open file!\n");
    return 1;
  }
                           

  char *int_status_key[] = {"ibuf_aio_reads",
                    "log_ios",
                    "sync_ios",
                    "io_reads",
                    "io_avg_bytes_read",
                    "io_writes",
                    "io_fsyncs",
                    "os_file_reads",
                    "os_file_writes",
                    "os_fsyncs",
                    "insert_num_of_merged_operations", /* INSERT BUFFER AND ADAPTIVE HASH INDEX */
                    "discard_op_insert",
                    "delete_mark",
                    "delete",
                    "discarded_op_delete_mark",
                    "discarded_op_delete",
                    "hash_searches",
                    "no_hash_searches", 
                    "log_io_per_second",                            
                    "total_memory_allocated",
                    "dictionary_memory_allocated",
                    "buffer_pool_size",
                    "free_buffer",
                    "database_pages",
                    "old_database_pages",
                    "modified_db_pages",
                    "youngs_per_second",
                    "non_youngs_per_second",
                    "page_read_per_second",
                    "page_create_per_second",
                    "page_write_per_second",
                    "buffer_pool_hit_reate",
                    "page_read_ahead_per_second",
                    "evicted_without_access",
                    "random_read_ahead_per_second",
                    "query_inside_innodb_row_op",
                    "query_in_queue",
                    "number_rows_inserted",
                    "number_rows_updated",
                    "number_rows_delete",
                    "number_rows_read",
                    "insert_row_per_second",
                    "update_row_per_second",
                    "deleter_row_per_second",
                    "read_row_per_second"
  };

  /* 获取指针数组元素的个数 */
  int arr_len = sizeof(int_status_key) /sizeof(char *);
  
  for(i = 0;i < arr_len;i++)
  {
    if(strcmp(status,int_status_key[i]) == 0)
      /* 获取索引号，即数组下标 */
      arr_index = i;  
  }
 
  const int real_index =  arr_index;
  
  //printf("int_status_key[%d] = %s\n",arr_index,int_status_key[arr_index]);
  
  while( fgets(buf,16,fd) != NULL) //每次读一行
  {
    len = strlen(buf);
    
    j++; //每读一行，自增1，与索引号比较

    /* 如果没有获取指定的索引号，直接跳过，不读取该行.
     * 另外，如果想要获取指针数组int_status_key第5个元素对应的值，那么，在文件里，应该跳过4行，
     * 第5行才是需要获取的值。而数组是从0开始算的，第5个元素对应的real_index的值是5，在if判断
     * 条件里，j从1开始数，所以比较的时候，j需要减1。这样才能保证读取到正确的值，如果使用j <
     * real_index作为条件的话，则只会读取到需要数值的前一个。
     */
    if( (j - 1) < real_index)
      continue;
    
    //printf("j = %d\n",j);
    for(i = 0; i < len -1 ;i++)
    {
      /* 读完一行，跳出*/
      if(buf[i] == '\n')
        break;
      //printf("%c",buf[i]);
      ret[i] = buf[i];
    }
    //printf("\n");
    ret[i] = '\0';
    break;
  }  
  // printf("ret = %s\n",ret);

  fclose(fd);
  return atof(ret);
}
